/*******************************************************************

    Author: Xiao
    Date: 2022/4/1 10:28

*******************************************************************/
package websocket

import (
	"encoding/json"
	"fmt"
	"mcr/pkg/dao"
	"mcr/pkg/logs"
	"mcr/pkg/utils"
	"strconv"
	"sync"
	"time"
)

type ClientManager struct {
	Clients     map[*Client]struct{} // 全部的连接
	ClientsLock *sync.RWMutex        // 读写锁
	Register    chan *Client         // 连接连接处理
	Unregister  chan *Client         // 断开连接处理程序
}

type SocketMessage struct {
	Type    string `json:"type"`
	Content string `json:"content"`
	Where   string `json:"where"`
	At      string `json:"at"`
	Name    string `json:"name"`
	Plat    string `json:"plat"`
}

// websocket客户端管理器
var SCM *ClientManager

// 初始化websocket管理器
func InitSocketManager() {
	SCM = &ClientManager{
		Clients:     make(map[*Client]struct{}),
		ClientsLock: new(sync.RWMutex),
		//Users:      make(map[string]*Client),
		//UserLock:	new(sync.RWMutex),
		Register:   make(chan *Client, 1000),
		Unregister: make(chan *Client, 1000),
	}
	go startMonitor()
	return
}

// 管道管理websocket管理器
func startMonitor() {
	for {
		select {
		case client := <-SCM.Register:
			// 建立连接事件
			client.EventRegister()
			logs.Log.Infof("现有总连接数:%d", len(SCM.Clients))
		case client := <-SCM.Unregister:
			// 断开连接事件
			client.EventUnregister()
			logs.Log.Infof("现有总连接数:%d", len(SCM.Clients))
		}
	}
}

// 用户建立连接事件
func (client *Client) EventRegister() {
	oldClients := GetClientsByTicket(client.Ticket)
	for _, c := range oldClients {
		c.UnConnectSocket()
		c.DelClientFromManager()
	}
	client.SetClientToManager()
	client.NowTimeSong()

	RefreshOnlineByRoom(client.RoomId)
	logs.Log.Infof("用户:%v(%s)房号:%d建立连接", client.UserId, client.Addr, client.RoomId)
}

// 用户离开连接事件
func (client *Client) EventUnregister() {
	client.DelClientFromManager()
	RefreshOnlineByRoom(client.RoomId)
	logs.Log.Infof("用户:%v(%s)房号:%d离开", client.UserId, client.Addr, client.RoomId)
}

// 断开连接
func (client *Client) UnConnectSocket() {
	err := client.Socket.Close()
	if err != nil {
		logs.Log.Errorf("用户:%v(%s)房号:%d断开连接时出错:%s", client.UserId, client.Addr, client.RoomId, err)
	}
}

// 设置连接到Manager
func (client *Client) SetClientToManager() {
	SCM.ClientsLock.Lock()
	defer SCM.ClientsLock.Unlock()
	SCM.Clients[client] = struct{}{}
}

// 从Manager中删除client
func (client *Client) DelClientFromManager() {
	SCM.ClientsLock.Lock()
	defer SCM.ClientsLock.Unlock()
	if _, ok := SCM.Clients[client]; ok {
		delete(SCM.Clients, client)
	}
}

// 获取房间内所有的用户连接
func GetClientsByRoom(rid int) (cs []*Client) {
	SCM.ClientsLock.Lock()
	defer SCM.ClientsLock.Unlock()
	for c, _ := range SCM.Clients {
		if c.RoomId == rid {
			cs = append(cs, c)
		}
	}
	return
}

// 获取用户所有的连接
func GetClientsByUser(uid string) (cs []*Client) {
	SCM.ClientsLock.Lock()
	defer SCM.ClientsLock.Unlock()
	for c, _ := range SCM.Clients {
		if c.UserId == uid {
			cs = append(cs, c)
		}
	}
	return
}

// 获取用户所有的连接
func GetClientsByTicket(ticket string) (cs []*Client) {
	SCM.ClientsLock.Lock()
	defer SCM.ClientsLock.Unlock()
	for c, _ := range SCM.Clients {
		if c.Ticket == ticket {
			cs = append(cs, c)
		}
	}
	return
}

// 发送消息到房间
func SendMsgToRoom(rid int, msg map[string]interface{}) {
	cs := GetClientsByRoom(rid)
	for _, c := range cs {
		err := c.Socket.WriteJSON(msg)
		if err != nil {
			logs.Log.Errorf("发送到用户:%s,房间:%s失败:%s", c.UserId, c.RoomId, err)
		}
	}
}

// 发送消息给所有人
func SendMsgToAll(msg map[string]interface{}) {
	for c, _ := range SCM.Clients {
		err := c.Socket.WriteJSON(msg)
		if err != nil {
			logs.Log.Errorf("发送到用户:%s,房间:%s失败:%s", c.UserId, c.RoomId, err)
		}
	}
}

// 发送消息给指定用户
func SendMsgToUser(uid string, msg map[string]interface{}) {
	cs := GetClientsByUser(uid)
	for _, c := range cs {
		err := c.Socket.WriteJSON(msg)
		if err != nil {
			logs.Log.Errorf("发送到用户:%s,房间:%s失败:%s", c.UserId, c.RoomId, err)
		}
	}
}

type OnlineUser struct {
	UserId       int    `json:"user_id"`
	UserIcon     int    `json:"user_icon"`
	UserAdmin    bool   `json:"user_admin"`
	UserShutdown bool   `json:"user_shutdown"`
	UserSongdown bool   `json:"user_songdown"`
	UserGuest    bool   `json:"user_guest"`
	UserSex      int    `json:"user_sex"`
	UserName     string `json:"user_name"`
	UserHead     string `json:"user_head"`
	UserRemark   string `json:"user_remark"`
	UserExtra    string `json:"user_extra"`
	UserDevice   string `json:"user_device"`
	UserTouchtip string `json:"user_touchtip"`
	UserVip      string `json:"user_vip"`
	UserGroup    int    `json:"user_group"`
}

// 获取用户信息到在线数据中
func GetUserOnlineData(uid int) (OnlineUser, error) {
	ui := OnlineUser{}
	u, err := dao.GetUserByUserId(uid)
	if err != nil {
		return ui, err
	}
	ui = OnlineUser{
		UserId:       u.UserId,
		UserTouchtip: u.UserTouchtip,
		UserSex:      u.UserSex,
		UserRemark:   u.UserRemark,
		UserHead:     u.UserHead,
		UserName:     u.UserName,
		UserDevice:   u.UserDevice,
		UserExtra:    u.UserExtra,
		UserIcon:     u.UserIcon,
		UserVip:      u.UserVip,
		UserGroup:    u.UserGroup,
		UserAdmin:    utils.GetIsAdmin(u.UserGroup),
	}
	return ui, nil
}

// 刷新房间的在线用户
func RefreshOnlineByRoom(rid int) {
	cs := GetClientsByRoom(rid)
	var users []OnlineUser
	// 登录在线的人员
	online := len(cs)
	// 所有在线人员
	realonline := len(cs)
	for _, c := range cs {
		uid, err := strconv.Atoi(c.UserId)
		if err != nil {
			name := utils.GetAddrPath(c.Addr)
			users = append(users, OnlineUser{
				UserId:   111111,
				UserName: name + "的游客",
			})
			online--
		} else {
			ui, err := GetUserOnlineData(uid)
			if err != nil {
				logs.Log.Errorf("获取用户信息失败:%s", err)
			}
			ui.UserGuest = GetCacheStatus("shutdown", rid, uid)
			ui.UserGuest = GetCacheStatus("songdown", rid, uid)
			ui.UserGuest = GetCacheStatus("guestctrl", rid, uid)
			users = append(users, ui)
		}
	}
	msgJson := make(map[string]interface{})
	msgJson["room_online"] = online
	msgJson["room_realonline"] = realonline
	err := dao.UpdateRoom(rid, msgJson)
	if err != nil {
		logs.Log.Errorf("更新房间的在线人数信息失败:%s", err)
	}
	msgJson = make(map[string]interface{})
	msgJson["type"] = "online"
	msgJson["channel"] = rid
	msgJson["data"] = users
	SendMsgToRoom(rid, msgJson)
}

func GetCacheStatus(t string, rid, uid int) bool {
	switch t {
	case "shutdown":
		if v, err := dao.GetCacheString(fmt.Sprintf("shutdown_room_%d_user_%d", rid, uid)); err == nil {
			if v == "true" {
				return true
			}
		}
	case "songdown":
		if v, err := dao.GetCacheString(fmt.Sprintf("songdown_room_%d_user_%d", rid, uid)); err == nil {
			if v == "true" {
				return true
			}
		}
	case "guestctrl":
		if v, err := dao.GetCacheString(fmt.Sprintf("guest_room_%d_user_%d", rid, uid)); err == nil {
			if v == "true" {
				return true
			}
		}
	}
	return false
}

// 用户信息
type userInfo struct {
	PassCount    int         `json:"pass_count"`
	PushCount    int         `json:"push_count"`
	UserAdmin    bool        `json:"user_admin"`
	UserId       int         `json:"user_id"`
	UserIcon     int         `json:"user_icon"`
	UserSex      int         `json:"user_sex"`
	UserName     string      `json:"user_name"`
	UserHead     string      `json:"user_head"`
	UserRemark   string      `json:"user_remark"`
	UserExtra    string      `json:"user_extra"`
	UserDevice   string      `json:"user_device"`
	UserTouchtip string      `json:"user_touchtip"`
	UserVip      string      `json:"user_vip"`
	UserGroup    int         `json:"user_group"`
	MyRoom       interface{} `json:"myRoom"`
}
type listSong struct {
	User      userInfo     `json:"user"`
	Song      dao.SongResp `json:"song"`
	At        interface{}  `json:"at"`
	PushCount int          `json:"push_count"`
	PushTime  int64        `json:"push_time"`
	Since     int64        `json:"since"`
}

// 现在房间播放的音乐
func (client *Client) NowTimeSong() {
	var lss []listSong
	listStr, err := dao.GetCacheString(fmt.Sprintf("SongList_%d", client.RoomId))
	if err == nil {
		err = json.Unmarshal([]byte(listStr), &lss)
		if err != nil {
			logs.Log.Errorf("解码歌曲列表失败:%s", err)
		}
	}
	r, err := dao.GetRoomById(client.RoomId)
	if err != nil {
		logs.Log.Errorf("房间查询失败:%s", err)
	}
	switch r.RoomType {
	case 1,4:
		//if len(lss) > 1 {
			sendMap := make(map[string]interface{})
			sendMap["type"] = "playSong"
			sendMap["time"] = time.Now().Format("15:04:05")
			sendMap["count"] = len(lss)
			var now listSong
			nowStr, err := dao.GetCacheString(fmt.Sprintf("SongNow_%d", client.RoomId))
			if err == nil {
				err = json.Unmarshal([]byte(nowStr), &now)
				if err != nil {
					logs.Log.Errorf("解码歌曲列表失败:%s", err)
				}
				sendMap["user"] = now.User
				if now.At == false {
					atMap := make(map[string]interface{})
					atMap["user_id"] = 0
					sendMap["at"] = atMap
				} else {
					sendMap["at"] = now.At
				}
				sendMap["song"] = now.Song
				sendMap["since"] = now.Since
				sendMap["now"] = time.Now().Unix()
			}
			err = client.Socket.WriteJSON(sendMap)
			if err != nil {
				logs.Log.Errorf("发送到用户:%s,房间:%s失败:%s", client.UserId, client.RoomId, err)
			}
		//}
	}
}
